Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 28, 2025

Inconsistent naming (command.rs vs subcommand.rs) and flat file structure made it unclear which commands had subcommands. This establishes two clear patterns.

Changes

Pattern 1 - Simple commands:

  • Renamed destroy/command.rshandler.rs

Pattern 2 - Commands with subcommands:

  • Created create/subcommands/ directory structure
  • Extracted subcommands/environment.rs (environment creation logic)
  • Extracted subcommands/template.rs (template generation logic)
  • Converted create/subcommand.rshandler.rs (now a simple router)

Documentation:

  • Added command structure patterns to docs/contributing/module-organization.md
  • Documented when to use each pattern with examples

Structure

// Pattern 1: Simple command
destroy/
  └── handler.rs              // Direct implementation

// Pattern 2: Command with subcommands  
create/
  ├── handler.rs              // Router
  └── subcommands/
      ├── environment.rs
      └── template.rs

// Router delegates to subcommands
pub fn handle_create_command(action: CreateAction, working_dir: &Path) -> Result<()> {
    match action {
        CreateAction::Environment { env_file } => 
            subcommands::handle_environment_creation(&env_file, working_dir),
        CreateAction::Template { output_path } => 
            subcommands::handle_template_generation(&output_path),
    }
}

All 46 tests passing, no behavioral changes.

Original prompt

This section details on the original issue you should resolve

<issue_title>Organize Subcommands in Dedicated Folder Structure and Standardize Module Organization</issue_title>
<issue_description>Parent Issue: #63
Type: 🎯 Quick Win
Impact: 🟢🟢🟢 High
Effort: 🔵🔵 Medium
Priority: P0

Problem

The naming inconsistency (subcommand.rs vs command.rs) and lack of standardized module organization creates confusion and makes it unclear which commands have subcommands.

Current structure:

create/
  ├── subcommand.rs       ← Has subcommands but flat structure
  └── ...

destroy/
  ├── command.rs          ← Single command
  └── ...

Proposed Solution

Create a clear distinction using folder structure and document it as the standard pattern:

For commands with subcommands (like create):

src/presentation/commands/create/
  ├── mod.rs
  ├── handler.rs                      // Main router
  ├── errors.rs
  ├── subcommands/                    // 🆕 Dedicated folder
  │   ├── mod.rs
  │   ├── environment.rs
  │   └── template.rs
  └── tests/

For single commands (like destroy):

src/presentation/commands/destroy/
  ├── mod.rs
  ├── handler.rs                      // Direct implementation
  ├── errors.rs
  └── tests/

Benefits

  • ✅ Clear visual distinction between simple and composite commands
  • ✅ Each subcommand has focused, single-responsibility module
  • ✅ Consistent handler.rs naming for all commands
  • ✅ Easy to add new subcommands without cluttering main files
  • ✅ Pattern is documented and clear for future commands

Implementation Checklist

Phase 1: Restructure destroy command:

  • Rename destroy/command.rs to handler.rs
  • Update destroy/mod.rs to use pub mod handler;
  • Update re-exports in destroy/mod.rs
  • Verify imports and tests still work

Phase 2: Restructure create command:

  • Create create/subcommands/ directory
  • Create create/subcommands/mod.rs
  • Extract environment creation to subcommands/environment.rs
  • Extract template generation to subcommands/template.rs
  • Rename create/subcommand.rs to handler.rs
  • Refactor handler.rs to be a simple router
  • Update create/mod.rs to include subcommands module
  • Update re-exports

Phase 3: Document the pattern:

  • Add module structure patterns to docs/contributing/module-organization.md
  • Document when to use each pattern
  • Add migration guide

Phase 4: Validation:

  • Update imports in all test files
  • Verify all tests pass
  • Run linter and fix any issues
  • Verify documentation builds

Acceptance Criteria

  • All files are renamed and moved according to the new structure
  • handler.rs is used consistently across all commands
  • Subcommands are in dedicated subcommands/ folder for create command
  • Documentation includes the new standardized pattern
  • All tests pass: cargo test presentation::commands
  • Pre-commit checks pass: ./scripts/pre-commit.sh
  • Code follows project conventions

Related Documentation

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Organize subcommands in dedicated folder structure Standardize command module structure with handler.rs and subcommands folder Oct 28, 2025
Copilot AI requested a review from josecelano October 28, 2025 22:01
Copilot finished work on behalf of josecelano October 28, 2025 22:01
@josecelano josecelano marked this pull request as ready for review October 29, 2025 06:52
Copy link
Member

@josecelano josecelano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 664e1c7

@josecelano josecelano merged commit c2b22ff into main Oct 29, 2025
48 checks passed
josecelano added a commit that referenced this pull request Oct 29, 2025
ec977df fix: update import path in merged template.rs file (copilot-swe-agent[bot])
5786545 chore: format code after refactoring (copilot-swe-agent[bot])
1bdb9c4 refactor: move config module from domain to create command handler (copilot-swe-agent[bot])
6e36037 Initial plan (copilot-swe-agent[bot])

Pull request description:

  ## ✅ Move config module from domain to create command handler - COMPLETE

  Successfully moved `src/domain/config/` to `src/application/command_handlers/create/config/` to align with DDD principles.

  ### Changes Summary

  **Module relocation:**
  - Moved `src/domain/config/` → `src/application/command_handlers/create/config/`
  - Updated module declarations in `src/domain/mod.rs` and `src/application/command_handlers/create/mod.rs`

  **Import path updates:**
  - Application layer: 5 files (handler, errors, tests)
  - Presentation layer: 4 files (config_loader, environment subcommand, errors, template subcommand)
  - Testing utilities: 1 file (e2e tasks)
  - Documentation: 20+ doc examples

  **Merge resolution:**
  - Merged changes from main branch (PR #74)
  - Fixed import path in new `template.rs` file created in merged PR

  ### Verification ✅

  - ✅ `cargo build` - compiles successfully
  - ✅ `cargo test --lib` - all 1002 tests pass
  - ✅ `cargo run --bin linter clippy` - no warnings
  - ✅ `cargo fmt` - formatting correct
  - ✅ Merge conflicts resolved successfully

  ### Impact

  This refactoring improves architecture by:
  - ✅ **DDD Compliance**: Removed DTOs from domain layer
  - ✅ **Higher Cohesion**: Config module now co-located with create command handler
  - ✅ **Clearer Boundaries**: Domain layer remains pure business logic
  - ✅ **Better Discoverability**: All create command code in one place
  - ✅ **No Breaking Changes**: Internal refactoring only

  ### Ready for Merge

  All verification steps complete. Merge conflicts resolved. The refactoring successfully aligns the codebase with DDD principles while maintaining all existing functionality.

  <!-- START COPILOT CODING AGENT SUFFIX -->

  <details>

  <summary>Original prompt</summary>

  >
  > ----
  >
  > *This section details on the original issue you should resolve*
  >
  > <issue_title>Move config module from domain to create command handler</issue_title>
  > <issue_description>## 📋 Overview
  >
  > Move the `src/domain/config/` module to `src/application/command_handlers/create/config/` to align with DDD principles and improve code organization.
  >
  > **Current Location (Incorrect):**
  > ```
  > src/domain/config/
  > ```
  >
  > **Target Location (Correct):**
  > ```
  > src/application/command_handlers/create/config/
  > ```
  >
  > ## 🎯 Problem
  >
  > The config module is currently misplaced in the domain layer, violating Domain-Driven Design principles:
  >
  > 1. **Serialization concerns in domain**: Uses `serde::Deserialize` for JSON parsing (data transfer concern, not business logic)
  > 2. **Infrastructure operations in domain**: Contains `generate_template_file()` with `tokio::fs` I/O operations
  > 3. **String-based primitives**: Uses raw `String` types instead of domain value objects (`EnvironmentName`, `Username`)
  > 4. **Acts as DTO**: Converts external formats to domain types via `to_environment_params()` - this is application layer responsibility
  > 5. **Low cohesion**: Exclusively used by create command but separated from it by layer boundaries
  >
  > ## ✅ Solution
  >
  > Move config module to be nested under the create command handler for:
  >
  > - ✅ **DDD compliance**: Removes DTOs from domain layer
  > - ✅ **Higher cohesion**: Config lives with its only consumer
  > - ✅ **Clearer boundaries**: Domain remains pure business logic
  > - ✅ **Better discoverability**: All create command code in one place
  > - ✅ **No premature abstraction**: No generic `dto/` folder for single use
  >
  > ## 📚 Documentation
  >
  > Full refactoring plan with detailed implementation checklist:
  > 👉 [docs/refactors/plans/move-config-to-create-command.md](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/refactors/plans/move-config-to-create-command.md)
  >
  > ## 📝 Implementation Steps
  >
  > The plan includes 9 major steps:
  >
  > 1. Create new directory structure
  > 2. Move all 4 files (`mod.rs`, `environment_config.rs`, `ssh_credentials_config.rs`, `errors.rs`)
  > 3. Update module declarations
  > 4. Update imports in application layer (5 files)
  > 5. Update imports in presentation layer (3 files)
  > 6. Update imports in testing utilities (1 file)
  > 7. Update documentation and doc examples
  > 8. Clean up old directory
  > 9. Comprehensive verification (build, test, lint, doc)
  >
  > ## 🧪 Testing
  >
  > - All existing tests must continue to pass
  > - No behavior changes, only import path updates
  > - Verification includes: `cargo build`, `cargo test`, linters, documentation
  >
  > ## 🏗️ Architecture
  >
  > This refactoring aligns with the project's DDD architecture where:
  >
  > - **Domain Layer**: Pure business logic, entities, value objects
  > - **Application Layer**: Use cases, command handlers, DTOs
  > - **Presentation Layer**: CLI, user interaction, config loading
  > - **Infrastructure Layer**: External tools, file system, SSH
  >
  > The config module is a DTO layer for the create command use case, hence belongs in application layer.
  >
  > ## ⏱️ Estimated Effort
  >
  > **Time**: 1-2 hours
  > **Complexity**: Medium (multiple file moves, import updates)
  > **Risk**: Low (no behavior changes, only structural)
  >
  > ## 🔗 Related
  >
  > - [Development Principles](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/development-principles.md)
  > - [DDD Architecture](https://github.com/torrust/torrust-tracker-deployer/blob/main/docs/codebase-architecture.md)
  > </issue_description>
  >
  > ## Comments on the Issue (you are @copilot in this section)
  >
  > <comments>
  > </comments>
  >

  </details>

  - Fixes #75

  <!-- START COPILOT CODING AGENT TIPS -->
  ---

  💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

ACKs for top commit:
  josecelano:
    ACK ec977df

Tree-SHA512: abb7f92e883fc049919f82383a76984ee29cc8416b18f0a0f0588e1d9e68a4e28cf9c560bb4e367ce4725c6f1c2c724e540131c41ad3314832c7a11713fd1a91
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Organize Subcommands in Dedicated Folder Structure and Standardize Module Organization

2 participants